/* 
 * Copyright (c) 2004-2005 Massachusetts Institute of Technology. This code was
 * developed as part of the Haystack (http://haystack.lcs.mit.edu/) research 
 * project at MIT. Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation files (the 
 * "Software"), to deal in the Software without restriction, including without 
 * limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom
 * the Software is furnished to do so, subject to the following conditions: 
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software. 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 */

/*
 * Created on Jun 13, 2004
 *
 */
package edu.mit.csail.relo.parts;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.ToolbarLayout;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.ImageDescriptor;
import org.openrdf.model.Resource;

import edu.mit.csail.relo.commands.AddNodeAndRelCmd;
import edu.mit.csail.relo.eclipse.gef.EditPartListener2;
import edu.mit.csail.relo.eclipse.gef.MenuButton;
import edu.mit.csail.relo.eclipse.gef.Triangle2;
import edu.mit.csail.relo.modelBridge.Artifact;
import edu.mit.csail.relo.store.StoreUtil;

/**
 * All edit parts should inherit from here, ArtifactEditPart's are for
 * anonymous/derive EditParts
 * 
 * @author vineet
 */
public abstract class MoreItemsEditPart extends ArtifactEditPart {
	

    private IFigure moreBtnFig = null;
    private IFigure innerMoreBtnFig = null;
	private Label moreLbl = null;
	private int totalChildrenCnt = -1;
	public IFigure getMoreBtn() {
	    if (moreBtnFig == null) {
	        totalChildrenCnt = getArtifact().getChildrenArtifacts(getRepo()).size();
	        moreBtnFig = createMoreButtonFig();
	        updateMoreButton();
	    }
	    return moreBtnFig;	    
	}
	protected List getVisibleEditPartChildren() {
	    // TODO: really get this from the model (is that possible with the anonymous nodes)
	    return getChildren();
	}
	protected void updateMoreButton() {
	    int curVisChildrenCnt = getVisibleEditPartChildren().size();
		
		String lblTxt = "";
	    lblTxt += (totalChildrenCnt-curVisChildrenCnt);
        //System.err.println(curVisChildrenCnt + ", " + totalChildrenCnt);
		//if (curChildrenCnt != 0)
		//	lblTxt += " More";
		
		String childrenLbl = getChildrenLabel();
		if (childrenLbl != null) lblTxt += " " + childrenLbl;
		
	    moreLbl.setText(lblTxt /*+ "... >>"*/);

		if (totalChildrenCnt == curVisChildrenCnt) {
            //moreBtnFig.setSize(0,0);
            //moreBtnFig.setVisible(false);
            //moreBtnFig.setEnabled(false);
            
            /*
            IFigure fig = new Figure();
            fig.setSize(2,2);
            fig.setBackgroundColor(ColorConstants.red);
            fig.setOpaque(true);
            moreBtnFig.add(fig);
            */
            if (!moreBtnFig.getChildren().isEmpty())
                moreBtnFig.remove(innerMoreBtnFig);
		} else {
		    //if (moreLbl.isOpaque())
		    //    moreLbl.setSize(moreLbl.getPreferredSize());
		    //moreLbl.setVisible(true);
		    //moreLbl.setEnabled(true);
            if (moreBtnFig.getChildren().isEmpty())
                moreBtnFig.add(innerMoreBtnFig);
		}
	}
	
	private Triangle2 getMoreButtonTriangle(int x, int y) {
        Triangle2 t;
        t = new Triangle2();
        t.setClosed(false);
        t.setFill(false);
        t.setBounds(new Rectangle(x, y, 5, 5));
    	t.setBackgroundColor(ColorConstants.listForeground);
    	t.setDirection(PositionConstants.EAST);
    	return t;
	}

    protected IFigure createMoreButtonFig() {
        moreLbl = new Label();
        moreLbl.setLabelAlignment(PositionConstants.LEFT);

        IFigure moreFig = new Figure();
        ToolbarLayout tb = new ToolbarLayout(true);
        tb.setMinorAlignment(ToolbarLayout.ALIGN_CENTER);
        moreFig.setLayoutManager(tb);
        moreFig.add(moreLbl);
        
        Figure dblArrowFig = new Figure();
    	dblArrowFig.add(getMoreButtonTriangle(1,2));
    	dblArrowFig.add(getMoreButtonTriangle(2,2));
    	dblArrowFig.add(getMoreButtonTriangle(5,2));
    	dblArrowFig.add(getMoreButtonTriangle(6,2));
    	dblArrowFig.setPreferredSize(11,8);
    	
        moreFig.add(dblArrowFig);
        
		MenuButton menuBtn = new MenuButton(moreFig, getViewer()) {
            @Override
            public void buildMenu(IMenuManager menu) {
                    menu.add(new Separator("main"));
                    buildMoreChildrenContextMenu(menu); 
            }};

		// update label
        addEditPartListener(new EditPartListener2.Stub() {
            @Override
            public void childAdded(EditPart child, int index) {
                updateMoreButton();
            }
        	@Override
            public void removedChild(EditPart child) {
                updateMoreButton();
        	}
        });

        innerMoreBtnFig = menuBtn;
        Figure moreBtn = new Figure();
        moreBtn.setLayoutManager(new ToolbarLayout());
        moreBtn.add(innerMoreBtnFig);
        return moreBtn;
    }
    
    private void buildMoreChildrenContextMenu(IMenuManager menu) {
        Set<Artifact> extraChildren = new HashSet<Artifact>(
        				getArtifact().
        					getChildrenArtifacts(
        							getRepo(),
        							StoreUtil.filterSubjectResPred(getRepo(), getRepo().rdfType, null)
        							));
        
        // remove visible items
        Iterator curChildrenIt = getVisibleEditPartChildren().iterator();
        while (curChildrenIt.hasNext()) {
            ArtifactEditPart childArt = (ArtifactEditPart) curChildrenIt.next();
            extraChildren.remove(childArt.getModel());
        }
        
        Map<String,Artifact> strToCUMap = getLabelsMap(extraChildren);        

        String[] strArray = strToCUMap.keySet().toArray(new String[] {});
        Arrays.sort(strArray);
        
        
        // create the actions
        for (int i=0; i<strArray.length; i++) {
            String extraActionLbl = strArray[i];
            Artifact extraArt = strToCUMap.get(extraActionLbl);
            
            IAction action = getAddNodeCmdAction(extraActionLbl, extraArt);
            menu.appendToGroup("main", action);
        }
    }
    private IAction getAddNodeCmdAction(String extraActionLbl, final Artifact extraArt) {
        final ReloController rc = (ReloController) getRoot().getContents();
        
        IAction action = new Action(extraActionLbl) {
            @Override
            public void run() {
                MoreItemsEditPart.this.execute(new AddNodeAndRelCmd(rc, extraArt));
            }
        };
        
        try {
            ImageDescriptor des = getIconDescriptor(extraArt, extraArt.getType(getRepo()));
            if (des != null) action.setImageDescriptor(des);
        } catch (Throwable t) {
            logger.error("Unexpected error while getting icon for: " + extraArt);
        }
        return action;
    }
    private Map<String, Artifact> getLabelsMap(Set<Artifact> artSet) {
        Map<String, Artifact> strToCUMap = new HashMap<String,Artifact> (artSet.size());
        for (Artifact art : artSet) {
            String lbl;
            try {
                lbl = getLabel(art, getArtifact());
            } catch (Throwable t) {
                logger.error("Unexpected error while getting label for: " + art);
                lbl = art.toString();
            }
            strToCUMap.put(lbl, art);
        }
        return strToCUMap;
    }

    protected String getChildrenLabel() {
        return null;
    }

    public String getLabel(Artifact art, Artifact contextArt) {
        return art.toString();
    }

    protected ImageDescriptor getIconDescriptor(Artifact art, Resource resType) {
    	return null;
    }


}
